// Copyright Epic Games, Inc. All Rights Reserved.

#include "LyraTeamDisplayAsset.h"

#include "Components/MeshComponent.h"
#include "NiagaraComponent.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "Engine/Texture.h"
#include "Teams/LyraTeamSubsystem.h"
#include "UObject/UObjectIterator.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraTeamDisplayAsset)

/**
 * 将团队显示资源应用到材质
 */
void ULyraTeamDisplayAsset::ApplyToMaterial(UMaterialInstanceDynamic* Material)
{
	if (Material) // 如果材质有效
	{
		for (const auto& KVP : ScalarParameters) // 遍历标量参数
		{
			Material->SetScalarParameterValue(KVP.Key, KVP.Value); // 设置标量参数值
		}

		for (const auto& KVP : ColorParameters) // 遍历颜色参数
		{
			Material->SetVectorParameterValue(KVP.Key, FVector(KVP.Value)); // 设置向量参数值
		}

		for (const auto& KVP : TextureParameters) // 遍历纹理参数
		{
			Material->SetTextureParameterValue(KVP.Key, KVP.Value); // 设置纹理参数值
		}
	}
}

/**
 * 将团队显示资源应用到网格组件
 */
void ULyraTeamDisplayAsset::ApplyToMeshComponent(UMeshComponent* MeshComponent)
{
	if (MeshComponent) // 如果网格组件有效
	{
		for (const auto& KVP : ScalarParameters) // 遍历标量参数
		{
			MeshComponent->SetScalarParameterValueOnMaterials(KVP.Key, KVP.Value); // 在材质上设置标量参数值
		}

		for (const auto& KVP : ColorParameters) // 遍历颜色参数
		{
			MeshComponent->SetVectorParameterValueOnMaterials(KVP.Key, FVector(KVP.Value)); // 在材质上设置向量参数值
		}

		const TArray<UMaterialInterface*> MaterialInterfaces = MeshComponent->GetMaterials(); // 获取材质接口
		for (int32 MaterialIndex = 0; MaterialIndex < MaterialInterfaces.Num(); ++MaterialIndex) // 遍历材质接口
		{
			if (UMaterialInterface* MaterialInterface = MaterialInterfaces[MaterialIndex]) // 如果材质接口有效
			{
				UMaterialInstanceDynamic* DynamicMaterial = Cast<UMaterialInstanceDynamic>(MaterialInterface); // 转换为动态材质实例
				if (!DynamicMaterial) // 如果不是动态材质
				{
					DynamicMaterial = MeshComponent->CreateAndSetMaterialInstanceDynamic(MaterialIndex); // 创建并设置动态材质实例
				}

				for (const auto& KVP : TextureParameters) // 遍历纹理参数
				{
					DynamicMaterial->SetTextureParameterValue(KVP.Key, KVP.Value); // 设置纹理参数值
				}
			}
		}
	}
}

/**
 * 将团队显示资源应用到Niagara组件
 */
void ULyraTeamDisplayAsset::ApplyToNiagaraComponent(UNiagaraComponent* NiagaraComponent)
{
	if (NiagaraComponent) // 如果Niagara组件有效
	{
		for (const auto& KVP : ScalarParameters) // 遍历标量参数
		{
			NiagaraComponent->SetVariableFloat(KVP.Key, KVP.Value); // 设置浮点变量
		}

		for (const auto& KVP : ColorParameters) // 遍历颜色参数
		{
			NiagaraComponent->SetVariableLinearColor(KVP.Key, KVP.Value); // 设置线性颜色变量
		}

		for (const auto& KVP : TextureParameters) // 遍历纹理参数
		{
			UTexture* Texture = KVP.Value; // 获取纹理
			NiagaraComponent->SetVariableTexture(KVP.Key, Texture); // 设置纹理变量
		}
	}
}

/**
 * 将团队显示资源应用到角色
 */
void ULyraTeamDisplayAsset::ApplyToActor(AActor* TargetActor, bool bIncludeChildActors)
{
	if (TargetActor != nullptr) // 如果目标角色有效
	{
		TargetActor->ForEachComponent(bIncludeChildActors, [this](UActorComponent* InComponent) // 遍历组件
		{
			if (UMeshComponent* MeshComponent = Cast<UMeshComponent>(InComponent)) // 如果是网格组件
			{
				ApplyToMeshComponent(MeshComponent); // 应用到网格组件
			}
			else if (UNiagaraComponent* NiagaraComponent = Cast<UNiagaraComponent>(InComponent)) // 如果是Niagara组件
			{
				ApplyToNiagaraComponent(NiagaraComponent); // 应用到Niagara组件
			}
		});
	}
}

#if WITH_EDITOR
/**
 * 属性编辑后变更
 */
void ULyraTeamDisplayAsset::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
	Super::PostEditChangeProperty(PropertyChangedEvent); // 调用父类方法

	for (ULyraTeamSubsystem* TeamSubsystem : TObjectRange<ULyraTeamSubsystem>()) // 遍历所有团队子系统
	{
		TeamSubsystem->NotifyTeamDisplayAssetModified(this); // 通知团队显示资源已修改
	}
}
#endif